package com.btl.service.ai.biz.adaptor;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.btl.boot.core.dto.response.R;
import com.btl.service.ai.auth.SecurityContextHolder;
import com.btl.service.ai.biz.entity.KwDocument;
import com.btl.service.ai.biz.entity.KwSegment;
import com.btl.service.ai.biz.facade.DocumentFacade;
import com.btl.service.ai.biz.service.IKwDocumentService;
import com.btl.service.ai.biz.service.IKwSegmentService;
import com.btl.service.ai.support.rag.embedding.strategy.EmbeddingModelTypeEnum;
import com.btl.service.ai.support.rag.embedding.strategy.EmbeddingStoreIngestorStrategy;
import com.btl.service.ai.support.rag.embedding.strategy.EmbeddingStoreIngestorStrategyFactory;
import com.btl.service.ai.support.input.common.split.strategy.SplitterEnum;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.filter.Filter;
import dev.langchain4j.store.embedding.filter.comparison.IsEqualTo;
import dev.langchain4j.store.embedding.filter.comparison.IsIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;

import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;

/**
 * 文档管理
 */
@Slf4j
@Validated
@RestController
@Tag(name = "文档")
@Controller
@RequestMapping("document")
public class KwDocumentController {

    @Resource
    private DocumentFacade documentFacade;

    @Resource
    private IKwDocumentService iKwDocumentService;

    @Resource
    private IKwSegmentService iKwSegmentService;

    /**
     * 通用文档
     *
     * @param splitter 分割方式
     * @param file     文件列表
     * @return List<SplitSegmentRsp>
     */
    @PostMapping(value = "/import", consumes = MULTIPART_FORM_DATA_VALUE)
    @Transactional(rollbackFor = Exception.class)
    public R<Long> imports(@RequestParam(value = "splitter", required = false) @NotNull(message = "分割器不能为空") SplitterEnum splitter,
                           @RequestParam(value = "file", required = false)
                           @NotNull(message = "文件不能为空") MultipartFile file) {
        return R.ok(documentFacade.createCommon(splitter, file));
    }

    /**
     * 对答文档
     *
     * @param file 文件列表
     * @return List<SplitSegmentRsp>
     */
    @PostMapping(value = "/reply/import", consumes = MULTIPART_FORM_DATA_VALUE)
    public R<Long> replayImports(@RequestParam(value = "file", required = false)
                                 @NotNull(message = "文件不能为空") MultipartFile file) {
        return R.ok(documentFacade.createReply(file));
    }


    /**
     * 文档分页
     *
     * @param current 当前页
     * @param size    每页数量
     * @return R<Page < KwDocument>>
     */
    @GetMapping("page")
    public R<Page<KwDocument>> page(@RequestParam(value = "current", required = false) @NotNull(message = "当前页码不能为空") Integer current,
                                    @RequestParam(value = "size", required = false) @NotNull(message = "每页数量不能为空") Integer size) {
        return R.ok(iKwDocumentService.page(current, size));
    }

    /**
     * 重新索引
     *
     * @param documentId 文档 id
     */
    @PutMapping("reindex/{documentId}")
    @Transactional(rollbackFor = Exception.class)
    public R<Map<String, Object>> reindex(@PathVariable @NotNull(message = "文档ID不能为空") Long documentId) {
        return R.ok(Map.of("documentId", documentFacade.reIndex(documentId)));
    }

    /**
     * 文档删除
     *
     * @param documentId 文档 id
     */
    @DeleteMapping("del/{documentId}")
    @Transactional(rollbackFor = Exception.class)
    public R<Map<String, Object>> del(@PathVariable @NotNull(message = "文档ID不能为空") Long documentId) {
        Long childId = SecurityContextHolder.get()
                .getChildId();
        KwDocument kwDocument = iKwDocumentService.getOne(new LambdaQueryWrapper<KwDocument>()
                .eq(KwDocument::getChildId, childId)
                .eq(KwDocument::getId, documentId));
        if (Objects.isNull(kwDocument)) {
            return R.fail("文档不存在");
        }
        iKwDocumentService.removeById(documentId);
        iKwSegmentService.remove(new LambdaQueryWrapper<KwSegment>()
                .eq(KwSegment::getDocumentId, documentId));
        Filter filter = new IsEqualTo("documentId", documentId.toString());
        String collectionName = "kw_segment";
        EmbeddingStoreIngestorStrategy embeddingStoreIngestorStrategy = EmbeddingStoreIngestorStrategyFactory.ingestorStrategy(EmbeddingModelTypeEnum.LOCAL_BGE_SMALL_ZH_V15_EMBEDDING_MODEL);
        EmbeddingStore<TextSegment> embeddingStore = embeddingStoreIngestorStrategy.embeddingStore(collectionName);
        embeddingStore.removeAll(filter);
        return R.ok(Map.of("documentId", documentId));
    }

    /**
     * 批量删除
     *
     * @param documentIds 文档 id 列表
     * @return R<List < Long>>
     */
    @DeleteMapping("del/batch")
    public R<List<Long>> batchDelete(@RequestBody List<Long> documentIds) {
        Long childId = SecurityContextHolder.get()
                .getChildId();
        List<KwDocument> kwDocumentList = iKwDocumentService.list(new LambdaQueryWrapper<KwDocument>()
                .eq(KwDocument::getChildId, childId)
                .in(KwDocument::getId, documentIds));
        List<Long> realDocumentIds = kwDocumentList.stream()
                .map(KwDocument::getId)
                .toList();
        if (CollectionUtils.isEmpty(realDocumentIds)) {
            return R.ok(new ArrayList<>());
        }
        iKwDocumentService.removeBatchByIds(realDocumentIds);
        String collectionName = "kw_segment";
        EmbeddingStoreIngestorStrategy embeddingStoreIngestorStrategy = EmbeddingStoreIngestorStrategyFactory.ingestorStrategy(EmbeddingModelTypeEnum.LOCAL_BGE_SMALL_ZH_V15_EMBEDDING_MODEL);
        EmbeddingStore<TextSegment> embeddingStore = embeddingStoreIngestorStrategy.embeddingStore(collectionName);
        List<String> realDocumentStrIds = realDocumentIds.stream()
                .map(Object::toString)
                .toList();
        Filter filter = new IsIn("documentId", realDocumentStrIds);
        embeddingStore.removeAll(filter);
        return R.ok(realDocumentIds);
    }

//
//    @GetMapping("test")
//    public List<Content> test(@RequestParam("query") String query) {
//        Document document = Document.from("""
//                 问：1.为什么我不能使用语音翻译？
//                 答：目前语音翻译只有专业版、体验版用户、标准套餐、字符套餐都支持，免费版用户是没有该功能的。如
//                    果您有语音翻译的需求，请联系客服升级成专业版后使用。
//                 问：2.为什么我不能使用截图翻译？
//                 答：目前截图翻译对除免费套餐外所有套餐开放，无法使用的唯一原因是达到了每日或每月的使用上限
//                    （200次/日、5000次/月）。
//                 问：3.为什么消息框下出现两条一样的文本？
//                 答：接收消息实时翻译是服务于整个聊天框内的消息的，开启后会在所有消息类型的虚线下方显示目标语
//                   言的翻译结果。如果您不想看到这种情况可以选择关闭，或将目标语言更换成其他语言。
//                """, new Metadata(Map.of("title", "问答题")));
////        List<Document> documents = List.of(Document.from("""
////                 答：目前语音翻译只有专业版、体验版用户、标准套餐、字符套餐都支持，免费版用户是没有该功能的。如
////                    果您有语音翻译的需求，请联系客服升级成专业版后使用。
////                """, new Metadata(Map.of("title", "1.为什么我不能使用语音翻译？"))), Document.from("""
////                答：目前截图翻译对除免费套餐外所有套餐开放，无法使用的唯一原因是达到了每日或每月的使用上限
////                   （200次/日、5000次/月）。
////                """, new Metadata(Map.of("title", "2.为什么我不能使用截图翻译？"))), Document.from("""
////                答：接收消息实时翻译是服务于整个聊天框内的消息的，开启后会在所有消息类型的虚线下方显示目标语
////                   言的翻译结果。如果您不想看到这种情况可以选择关闭，或将目标语言更换成其他语言。
////                """, new Metadata(Map.of("title", "3.为什么消息框下出现两条一样的文本？"))), Document.from("""
////                答：源语言是输入框内的文本；目标语言是在消息框上方的文本（给客户看的）；
////                    注意：如果已选择一种源语言如英语，但却输入的是中文，目标语言为日语。那么本次翻译中系统将
////                    会输入的语言自动识别并转变为源语言，即便源语言和输入的语言不同，系统会自动识别后再翻译。
////                """, new Metadata(Map.of("title", "4.什么是源语言、目标语言，他们分别对应什么？"))), Document.from("""
////                答：目前我们支持翻译的语种有208种，涵盖了全球绝大部分国家的语言。
////                """, new Metadata(Map.of("title", "5.目前翻译器支持多少种语言的翻译？"))), Document.from("""
////                答：为了预防这种情况，我们系统内可以在打开 【 发送翻译设置 】 的情况下，先在输入框内输入您需要发
////                  送的文字，按住Ctrl+T，此时输入框内的文字就进行自动翻译,您可以自行查看该翻译结果；或者Alt+T，翻译的译文会重新再翻译成你的输入语言来对比真实的语义；或者转
////                  到聚合翻译内，输入您刚才翻译的译文重译一遍，可以提前知道译文的真实含义，或者开启实时翻
////                  译， 翻译后的内容会在输入框上方随着您的输入实时翻译，方便您对照翻译效果。如果您不小心已经
////                  发送了不合时宜的译文，可以选择删除或撤回。
////                """, new Metadata(Map.of("title", "6.翻译时候发送出去的结果不是我想要的怎么办？"))));
//        DocumentSplitter documentSplitter = SplitStrategyFactory.getDocumentSplitter(SplitterEnum.FAQ_SPLITTER);
//        EmbeddingStoreIngestorStrategy embeddingStoreIngestorStrategy = EmbeddingStoreIngestorStrategyFactory.ingestorStrategy(EmbeddingModelTypeEnum.LOCAL_BGE_SMALL_ZH_V15_EMBEDDING_MODEL);
//        String collectionName = "kw_segment";
//        IngestionResult embed = embeddingStoreIngestorStrategy.embed(collectionName, documentSplitter, List.of(document));
//        return List.of();
//    }
//
//
//    /**
//     * 向量检索
//     *
//     * @param search 查询条件
//     * @return List<SplitSegmentRsp>
//     */
//    @Transactional
//    @GetMapping(value = "/retriever")
//    public R<Void> retriever(@RequestParam(value = "search", required = false) String search) {
//        String collectionName = "kw_segment";
//        RetrieverStrategy retrieverStrategy = RetrieverStrategyFactory.retrieverStrategy(EmbeddingModelTypeEnum.LOCAL_BGE_SMALL_ZH_V15_EMBEDDING_MODEL);
//        List<Content> s = retrieverStrategy.retriever(collectionName, new Query(search));
//        s.forEach(System.out::println);
//        AiAgent aiAgent = new AiAgent();
//        aiAgent.setPrompt(search);
//        aiAgent.setModelEnum("dd");
//        AiAgent save = aiAgentRepository.save(aiAgent);
//        aiAgentRepository.getReferenceById(save.getId());
//        aiAgentRepository.findById(save.getId());
//        System.out.println(save.getId());
//        return R.ok();
//    }
//
//    @Resource
//    private AiAgentRepository aiAgentRepository;
//
//    /**
//     * 增强生成
//     *
//     * @param search 查询条件
//     * @return List<SplitSegmentRsp>
//     */
//    @GetMapping(value = "/generate")
//    public R<String> generate(@RequestParam(value = "search", required = false) String search) {
//        String collectionName = "kw_segment";
//        GenerationKnowledgeStrategy strategy = GenerationKnowledgeFactory.getStrategy(GenerationModelEnum.OPEN_AI_CHAT_MODEL);
//        RetrieverStrategy retrieverStrategy = RetrieverStrategyFactory.retrieverStrategy(EmbeddingModelTypeEnum.LOCAL_BGE_SMALL_ZH_V15_EMBEDDING_MODEL);
//        List<Content> s = retrieverStrategy.retriever(collectionName, new Query(search));
//        String memoryId = "kw_segment_p_id";
//        Result<String> generate = strategy.generate(memoryId, s, new Query(search));
//        System.out.println(generate.finalResponse());
//        System.out.println(generate.sources());
//        System.out.println(generate.tokenUsage());
//        System.out.println(generate.finishReason());
//        System.out.println(generate.toolExecutions());
//        System.out.println(generate.intermediateResponses());
//        return R.ok();
//    }
//
//    /**
//     * 增强生成
//     *
//     * @param search 查询条件
//     * @return List<SplitSegmentRsp>
//     */
//    @GetMapping(value = "/query")
//    public R<String> query(@RequestParam(value = "search", required = false) String search,
//                           @RequestParam(value = "messages", required = false) String messages) {
//        SystemAndUserMessageTransformer queryTransformer = new SystemAndUserMessageTransformer(messages);
//        SystemAndUserMessageTransformer.Message transform = queryTransformer.transform(Query.from(search));
//        String memoryId = "test-a";
//        GenerationAssistantStrategy strategy = GenerationAssistantFactory.getStrategy(GenerationModelEnum.OPEN_AI_CHAT_MODEL);
//        Result<String> generate = strategy.generate(memoryId, transform.systemMessage(), transform.userMessage(), new Query(search));
//        return R.ok(generate.content());
//    }


}
